package com.zilue.hfqueue.channel;

import java.lang.management.ManagementFactory;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.text.NumberFormat;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 1位固定值+9位空闲值+20位mac地址（16进制 -> 10进制）+12位ip+6位进程ID+ 时间戳（13位） + 序列号（3位）
 * Created by zilue on 2017/4/22.
 */
public class UID {
    private static final Long DEFAULT_MAX_PER_MILLISECOND = 999L;
    private static AtomicLong atomicLong = new AtomicLong(0L);
    private static AtomicLong atomicTime = new AtomicLong(System.currentTimeMillis());

    private static String number_ip;
    private static String number_mac;
    private static String number_constant;
    private static String number_thread;
    private static NumberFormat sequenceFormat;

    static {
        try {
            InetAddress inetAddress = InetAddress.getLocalHost();
            String ip = inetAddress.getHostAddress().replace(".", "");
            NumberFormat numberFormat = NumberFormat.getNumberInstance();
            numberFormat.setGroupingUsed(false);
            numberFormat.setMinimumIntegerDigits(12);
            number_ip = numberFormat.format(Long.parseLong(ip));

            byte[] macBytes = NetworkInterface.getByInetAddress(inetAddress).getHardwareAddress();
            number_mac = new BigInteger(1, macBytes).toString(10);
            numberFormat.setGroupingUsed(false);
            numberFormat.setMinimumIntegerDigits(20);
            number_mac = numberFormat.format(Long.parseLong(number_mac));

            numberFormat.setMinimumIntegerDigits(9);
            number_constant = numberFormat.format(0);

            int tid = Integer.valueOf(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]).intValue();
            numberFormat.setMinimumIntegerDigits(6);
            number_thread = numberFormat.format(tid);

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (SocketException e) {
            e.printStackTrace();
        }
        sequenceFormat = NumberFormat.getNumberInstance();
        int seuquenceLen = String.valueOf(DEFAULT_MAX_PER_MILLISECOND).length();
        sequenceFormat.setMinimumIntegerDigits(seuquenceLen);
        sequenceFormat.setGroupingUsed(false);

    }

    public static void main(String[] args) throws UnknownHostException, SocketException {
        // 此方法需要JDK1.6。
        TestThread thread1 = new TestThread();
        TestThread thread2 = new TestThread();
        TestThread thread3 = new TestThread();
        TestThread thread4 = new TestThread();
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }


    /*获取64位唯一id*/
    public static String getLongUniqueId() {
        String formatSequence = sequenceFormat.format(getSequence());
        return 1 + number_constant + number_mac + number_ip + number_thread + System.currentTimeMillis() + formatSequence;
    }


    /**
     * get a sequence（number） in a millisecond,if sequenceNumber equels maxPerMillisecond,
     * it will return at next millisecond with a sequenceNumber which will increase from zero again
     *
     * @return
     */
    public static Long getSequence() {
        long nextSequence = atomicLong.get();
        while (nextSequence >= DEFAULT_MAX_PER_MILLISECOND || !atomicLong.compareAndSet(nextSequence, ++nextSequence)) {
            if (nextSequence >= DEFAULT_MAX_PER_MILLISECOND && atomicTime.longValue() >= System.currentTimeMillis()) {
                nextSequence = atomicLong.get();
            } else if (nextSequence >= DEFAULT_MAX_PER_MILLISECOND) {
                if (atomicLong.compareAndSet(DEFAULT_MAX_PER_MILLISECOND, 0)) {
                    atomicTime.set(System.currentTimeMillis());
                    nextSequence = 0L;
                }
            }
        }
        return nextSequence;
    }


}

class TestThread extends Thread {
    @Override
    public void run() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 2000; i++) {
            System.out.println(UID.getLongUniqueId());
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}